home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint112s.zoo / tty.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-14  |  33.1 KB  |  1,316 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * read/write routines for TTY devices
  9.  */
  10.  
  11. #include "mint.h"
  12.  
  13. /* emulate mdm0 ioctls too */
  14. #define MDM0_IOCTLS
  15. #ifdef MDM0_IOCTLS
  16. #define TIOCGHUPCL    (('T'<< 8) | 98)
  17. #define TIOCSHUPCL    (('T'<< 8) | 99)
  18. #define TIOCGSOFTCAR    (('T'<< 8) | 100)
  19. #define TIOCSSOFTCAR    (('T'<< 8) | 101)
  20. #endif
  21.  
  22. static void _erase P_((FILEPTR *, int, int));
  23. static int escseq P_((struct tty *, int));
  24.  
  25. /* setting a special character to this value disables it */
  26. #define UNDEF 0
  27.  
  28. #define HAS_WRITEB(f)    (((f)->fc.fs != &bios_filesys || \
  29.              (((struct bios_file *)(f)->fc.index)->drvsize > \
  30.                 offsetof (DEVDRV, writeb))) && \
  31.              (f)->dev->writeb)
  32. extern FILESYS bios_filesys;
  33.  
  34. /* default terminal characteristics */
  35.  
  36. struct tty default_tty = {
  37.     0,            /* process group */
  38.     0,            /* state */
  39.     0,            /* use_cnt */
  40.     0,            /* aux_cnt */
  41.     {
  42.     13, 13,            /* input speed == output speed == 9600 baud */
  43.     CTRL('H'),        /* erase */
  44.     CTRL('U'),        /* kill */
  45.     T_ECHO|T_CRMOD|T_TOSTOP|T_XKEY|T_ECHOCTL, /* flags */
  46.     },
  47.     {
  48.     CTRL('C'),        /* interrupt */
  49.     CTRL('\\'),        /* quit */
  50.     CTRL('Q'),        /* start */
  51.     CTRL('S'),        /* stop */
  52.     CTRL('D'),        /* EOF */
  53.     '\r'            /* alternate end of line */
  54.     },
  55.     {
  56.     CTRL('Z'),        /* suspend */
  57.     CTRL('Y'),        /* suspend after read */
  58.     CTRL('R'),        /* reprint */
  59.     CTRL('O'),        /* flush output */
  60.     CTRL('W'),        /* erase word */
  61.     CTRL('V')        /* quote next char */
  62.     },
  63.     {
  64.     0, 0, 0, 0        /* window size is unknown */
  65.     },
  66.     0,            /* no process is selecting us for reading */
  67.     0,            /* or for writing */
  68.     0,            /* use default XKEY map */
  69.     0,            /* not currently hanging up */
  70.     1, 0            /* RAW reads need 1 char, no timeout */
  71. };
  72.  
  73. #define _put(f, c) (tty_putchar((f), (c), RAW))
  74.  
  75. static void
  76. _erase(f, c, mode)
  77.     FILEPTR *f;
  78.     int c, mode;
  79. {
  80.     _put(f, '\010');
  81.     _put(f, ' ');
  82.     _put(f, '\010');
  83. /* watch out for control characters -- they're printed as e.g. "^C" */
  84. /* BUG: \t is messed up. We really need to keep track of the output
  85.  * column
  86.  */
  87.     if ((mode & T_ECHOCTL) && c >= 0 && c < ' ' && c != '\t') {
  88.         _put(f, '\010'); _put(f, ' '); _put(f, '\010');
  89.     }
  90. }
  91.  
  92. #define put(f, c)   { if (mode & T_ECHO) _put(f, c); }
  93. #define erase(f, c) { if (mode & T_ECHO) _erase(f, c, mode); }
  94.  
  95. long
  96. tty_read(f, buf, nbytes)
  97.     FILEPTR *f;
  98.     void *buf;
  99.     long nbytes;
  100. {
  101.     long r;
  102.     long bytes_read = 0;
  103.     unsigned char ch, *ptr;
  104.     int rdmode, mode;
  105.     struct tty *tty;
  106.  
  107.     tty = (struct tty *)f->devinfo;
  108.     assert(tty != 0);
  109.  
  110.     if (f->flags & O_HEAD) {    /* pty server side? */
  111.         rdmode = RAW;        /* yes -- always raw mode */
  112.         mode = T_RAW;
  113.     }
  114.     else if (curproc->domain == DOM_MINT) {    /* MiNT domain process? */
  115.         mode = tty->sg.sg_flags;
  116.         rdmode = COOKED|NOECHO;
  117.         if ( mode & (T_RAW | T_CBREAK) ) {
  118.             rdmode = (mode & T_RAW) ? RAW : COOKED;
  119.         }
  120.         if (mode & T_XKEY)
  121.             rdmode |= ESCSEQ;
  122.     }
  123.     else {
  124.         rdmode = COOKED|NOECHO;
  125.         mode = T_TOS | T_ECHO | T_ECHOCTL;
  126.     }
  127.  
  128.     if (nbytes == 0) return bytes_read;
  129.  
  130.     /* if RAW or CBREAK do VTIME:  select for input, return on timeout */
  131.     if (tty->vtime && (mode & (T_RAW|T_CBREAK)) &&
  132.         !(f->flags & (O_NDELAY|O_HEAD)) &&
  133.         (!(tty->state & TS_ESC) || !(rdmode & ESCSEQ))) {
  134.         long r, bytes = 0;
  135.  
  136.         if ((r = (*f->dev->select)(f, (long)curproc, O_RDONLY)) != 1) {
  137.             TIMEOUT *t;
  138.  
  139.             curproc->wait_cond = (long)wakeselect;    /* flag */
  140.             t = addtimeout((long)tty->vtime, (void (*)P_((PROC *)))wakeselect);
  141.             if (!t) {
  142.                 (*f->dev->unselect)(f, (long)curproc, O_RDONLY);
  143.                 return ENSMEM;
  144.             }
  145.             while (curproc->wait_cond == (long)wakeselect) {
  146.                 TRACE(("sleeping in tty_read (VTIME)"));
  147.                 if (sleep(SELECT_Q|0x100, (long)wakeselect))
  148.                     break;
  149.             }
  150.             canceltimeout(t);
  151.         }
  152.         (void)(*f->dev->ioctl)(f, FIONREAD, &bytes);
  153.         if (!r) {
  154.             extern short select_coll;    /* in dosfile.c */
  155.             (*f->dev->unselect)(f, (long)curproc, O_RDONLY);
  156.             wake(SELECT_Q, (long)&select_coll);
  157.         }
  158.         if (!bytes)
  159.             return bytes_read;
  160.     }
  161. #if 1
  162.     /* see if we can do fast RAW byte IO thru the device driver... */
  163.     if (rdmode == RAW &&
  164.         (!(tty->state & TS_ESC) || !(rdmode & ESCSEQ) ||
  165.         (f->flags & O_HEAD)) &&
  166.         (f->fc.fs != &bios_filesys ||
  167.         (nbytes > 1 &&
  168.          ((struct bios_file *)f->fc.index)->drvsize >
  169.             offsetof (DEVDRV, readb))) &&
  170.         f->dev->readb &&
  171.         ((f->flags & O_HEAD) || ((tty->state &= ~TS_COOKED), !tty->pgrp) ||
  172.         tty->pgrp == curproc->pgrp ||
  173.         f->fc.dev != curproc->control->fc.dev ||
  174.         f->fc.index != curproc->control->fc.index) &&
  175.         !(tty->state & TS_BLIND) &&
  176.         (r = (*f->dev->readb)(f, buf, nbytes)) != EUNDEV)
  177.         return r;
  178. #endif
  179.  
  180.     ptr = buf;
  181.  
  182.     while (bytes_read < nbytes) {
  183.         r = tty_getchar(f, rdmode);
  184.         if (r < 0) {
  185. tty_error:
  186.             DEBUG(("tty_read: tty_getchar returned %ld", r));
  187.             return (bytes_read) ? bytes_read : r;
  188.         }
  189.         else if (r == MiNTEOF)
  190.             return bytes_read;
  191.         ch = r & 0xff;
  192.  
  193.         if ( (rdmode & COOKED) && (mode & T_CRMOD) && (ch == '\r') )
  194.             ch = '\n';
  195.  
  196. /* 1 character reads in TOS mode are always raw */
  197.         if (nbytes == 1 && (mode & T_TOS)) {
  198.             put(f, ch);
  199.             *ptr = ch;
  200.             return 1;
  201.         }
  202.  
  203. /* T_CBREAK mode doesn't do erase or kill processing */
  204. /* also note that setting a special character to UNDEF disables it */
  205.  
  206.         if (rdmode & COOKED && !(mode & T_CBREAK) && ch != UNDEF) {
  207.             if ((char)ch == tty->sg.sg_erase) {  /* backspace */
  208.                 if (bytes_read > 0) {
  209.                     --ptr;
  210.                     erase(f, *ptr);
  211.                     bytes_read--;
  212.                 }
  213.                 continue;
  214.             }
  215.             else if ((mode & T_TOS) && ch == CTRL('X')) {
  216.                 while (bytes_read > 0) {
  217.                     --ptr;
  218.                     erase(f, *ptr);
  219.                     bytes_read--;
  220.                 }
  221.                 continue;
  222.             }
  223.             else if ((char)ch ==tty->ltc.t_rprntc || 
  224.                  (char)ch == tty->sg.sg_kill) {
  225.                 if (mode & T_TOS)
  226.                     put(f, '#');
  227.                 put(f, '\r');
  228.                 put(f, '\n');
  229.                 ptr = buf;
  230.                 if ((char)ch == tty->sg.sg_kill) {
  231.                     bytes_read = 0;
  232.                 }
  233.                 else {
  234.                     for (r = 0; r < bytes_read; r++, ptr++)
  235.                         put(f, *ptr);
  236.                 }
  237.                 continue;
  238.             }
  239.             else if ((char)ch == tty->ltc.t_werasc) {
  240.                 while (bytes_read > 0 &&
  241.                        !(ptr[-1] == ' ' || ptr[-1] == '\t')) {
  242.                     ptr--;
  243.                     erase(f, *ptr);
  244.                     bytes_read--;
  245.                 }
  246.                 continue;
  247.             }
  248.             else if ((char)ch == tty->ltc.t_lnextc) {
  249.                 if (mode & T_ECHOCTL) {
  250.                     put(f, '^');
  251.                     put(f, '\b');
  252.                 }
  253.                 r = tty_getchar(f, RAW);
  254.                 if (rdmode & COOKED)
  255.                     tty->state |= TS_COOKED;
  256.                 else
  257.                     tty->state &= ~TS_COOKED;
  258.  
  259.                 if (r < 0)
  260.                     goto tty_error;
  261.                 else if (r == MiNTEOF)
  262.                     return bytes_read;
  263.                 ch = r & 0xff;
  264.                 goto stuff_it;
  265.             }
  266.             else if ((char)ch == tty->tc.t_eofc && !(mode & T_TOS))
  267.                 return bytes_read;
  268.         }
  269.  
  270. /* both T_CBREAK and T_COOKED modes have to do signals, though */
  271.         if ((rdmode & COOKED) && ch != UNDEF) {
  272.             if ((char)ch == tty->tc.t_intrc
  273.                  || (char)ch == tty->tc.t_quitc
  274.                  || (char)ch == tty->ltc.t_dsuspc
  275.                  || (char)ch == tty->ltc.t_suspc
  276.                 ) {
  277. /* the device driver raised the appropriate signal; if we get here, the
  278.    signal was caught by the user (or ignored). flush buffers and continue
  279.  */
  280.                 if (!(tty->sg.sg_flags & T_NOFLSH)) {
  281.                     DEBUG(("tty_read: flushing input"));
  282.                     bytes_read = 0;
  283.                     ptr = buf;
  284.                 }
  285.                 continue;
  286.             }
  287.             else if ((char)ch == tty->ltc.t_flushc) {
  288.                 continue;
  289.             }
  290.             else if (ch == '\n' || (char)ch == tty->tc.t_brkc) {
  291.                 put(f, '\r');
  292.                 if (!(mode & T_TOS)) {
  293.                     *ptr = ch;
  294.                     put(f, '\n');
  295.                     bytes_read++;
  296.                 if (rdmode & COOKED)
  297.                     tty->state |= TS_COOKED;
  298.                 else
  299.                     tty->state &= ~TS_COOKED;
  300.                 }
  301.                 return bytes_read;
  302.             }
  303.  
  304.         }
  305.  
  306. /* do the following for both RAW and COOKED mode */
  307. stuff_it:
  308.         *ptr++ = ch;
  309.         if ((mode & T_ECHOCTL) &&
  310.             ch < ' ' && ch != '\t') {    /* ch is unsigned */
  311.             put(f, '^'); put(f, ch+'@');
  312.         }
  313.         else
  314.             put(f, ch);
  315.         bytes_read++;
  316.  
  317. /* for RAW mode, if there are no more characters then break */
  318.         if ( (mode & (T_RAW|T_CBREAK)) &&
  319.             !((rdmode & ESCSEQ) && (tty->state & TS_ESC))) {
  320.             r = 1;
  321.             (void)(*f->dev->ioctl)(f, FIONREAD, &r);
  322.             if (r <= 0) break;
  323.         }    
  324.     }
  325.     if (rdmode & COOKED)
  326.         tty->state |= TS_COOKED;
  327.     else
  328.         tty->state &= ~TS_COOKED;
  329.     return bytes_read;
  330. }
  331.  
  332. /* job control checks */
  333. /* AKP: added T_TOSTOP; don't stop BG output if T_TOSTOP is clear */
  334. /*
  335. entropy: only do the job control if SIGTTOU is neither blocked nor ignored,
  336. and only for the controlling tty (IEEE 1003.1-1990 7.1.1.4 79-87).
  337. BUG:  if the process group is orphaned and SIGTTOU *is not* blocked
  338. or ignored, we should return EIO instead of signalling.
  339. */
  340. INLINE void
  341. tty_checkttou (f, tty)
  342.     FILEPTR *f;
  343.     struct tty *tty;
  344. {
  345.     if (tty->pgrp && tty->pgrp != curproc->pgrp &&
  346.              (tty->sg.sg_flags & T_TOSTOP) &&
  347.                  (curproc->sighandle[SIGTTOU] != SIG_IGN) &&
  348.                  ((curproc->sigmask & (1L << SIGTTOU)) == 0L) &&
  349.                  (f->fc.dev == curproc->control->fc.dev) &&
  350.                  (f->fc.index == curproc->control->fc.index)) {
  351.         TRACE(("job control: tty pgrp is %d proc pgrp is %d",
  352.             tty->pgrp, curproc->pgrp));
  353.         killgroup(curproc->pgrp, SIGTTOU, 1);
  354.         check_sigs();
  355.     }
  356. }
  357.  
  358. long
  359. tty_write(f, buf, nbytes)
  360.     FILEPTR *f;
  361.     const void *buf;
  362.     long nbytes;
  363. {
  364.     unsigned const char *ptr;
  365.     long c;
  366.     long bytes_written;
  367.     int mode, rwmode;
  368.     struct tty *tty;
  369.     int use_putchar = 0;
  370.     static long cr_char = '\r';
  371. #define LBUFSIZ 128
  372.     long lbuf[LBUFSIZ];
  373.  
  374.     tty = (struct tty *)f->devinfo;
  375.     assert(tty != 0);
  376.  
  377.     ptr = (unsigned const char *)buf;
  378.     if (f->flags & O_HEAD) {
  379.         use_putchar = 1;
  380.         mode = T_RAW;
  381.     }
  382.     else if (curproc->domain == DOM_TOS)
  383. /* for TOS programs, 1 byte writes are always in raw mode */
  384.         mode = (nbytes == 1) ? T_RAW : T_TOS;
  385.     else
  386.         mode = tty->sg.sg_flags;
  387.  
  388.     rwmode = (mode & T_RAW) ? RAW : COOKED;
  389.  
  390.     bytes_written = 0;
  391.  
  392. /*
  393.  * "mode" can now be reduced to just T_CRMODE or not
  394.  */
  395.     if ((curproc->domain == DOM_MINT) && (mode & T_CRMOD) &&
  396.         !(mode & T_RAW))
  397.         mode = T_CRMOD;
  398.     else
  399.         mode = 0;
  400.  
  401.     if (nbytes == 0) return bytes_written;
  402. #if 1
  403.     /* see if we can do fast RAW byte IO thru the device driver... */
  404.     if (!use_putchar && HAS_WRITEB(f)) {
  405.  
  406.         tty_checkttou (f, tty);
  407.         if (rwmode & COOKED)
  408.             tty->state |= TS_COOKED;
  409.         else
  410.             tty->state &= ~TS_COOKED;
  411.         if (tty->state & TS_BLIND)
  412.             return bytes_written;
  413.         if (mode) {    /* i.e. T_CRMODE */
  414.             if ((*f->dev->writeb)(f, buf, 0L) != EUNDEV) {
  415.     /* write in big chunks if possible; lines if CRMODE
  416.      * (if we get here flow control is taken care of by the device)
  417.      */
  418.                 long bytes_to_write = 0;
  419.                 unsigned const char *s = ptr;
  420.  
  421.                 while (nbytes-- > 0) {
  422.                     if (*ptr++ == '\n') {
  423.                         if (0 != (bytes_to_write = ptr-s-1)) {
  424.                             c = (*f->dev->writeb)(f, (const char *)s,
  425.                                 bytes_to_write);
  426.                             bytes_written += c;
  427.                             if (c != bytes_to_write) {
  428.                                 if (c < 0)
  429.                                     bytes_written = c;
  430.                                 return bytes_written;
  431.                             }
  432.                         }
  433.                         s = ptr-1;
  434.                         c = (*f->dev->writeb)(f, "\r", 1);
  435.                         if (c != 1) {
  436.                             if (c < 0)
  437.                                 bytes_written = c;
  438.                             return bytes_written;
  439.                         }
  440.                     }
  441.                 }
  442.                 if (0 != (bytes_to_write = ptr-s)) {
  443.                     c = (*f->dev->writeb)(f, (const char *)s, bytes_to_write);
  444.                     bytes_written += c;
  445.                     if (c < 0)
  446.                         bytes_written = c;
  447.                 }
  448.                 return bytes_written;
  449.             }
  450.         } else if ((c = (*f->dev->writeb)(f, buf, nbytes)) != EUNDEV)
  451.             return c;
  452.     }
  453. #endif
  454.  
  455. /*
  456.  * we always write at least 1 byte with tty_putchar, since that takes
  457.  * care of job control and terminal states. After that, we may be able
  458.  * to use (*f->dev->write) directly.
  459.  */
  460.  
  461.     c = *ptr++;
  462.  
  463.     if (c == '\n' && mode) {    /* remember, "mode" now means CRMOD */
  464.         tty_putchar(f, cr_char, rwmode);
  465.     }
  466.     tty_putchar(f, c, rwmode);
  467.     nbytes--;
  468.     bytes_written++;
  469.  
  470.     if (use_putchar) {
  471.         while (nbytes-- > 0) {
  472.             c = *ptr++;
  473.             if (c == '\n' && mode)
  474.                 tty_putchar(f, cr_char, rwmode);
  475.             tty_putchar(f, c, rwmode);
  476.             bytes_written++;
  477.         }
  478.     } else {
  479. /* write in big chunks if possible; but never more than 1 line
  480.  * (so that ^S/^Q can happen reasonably quickly for the user)
  481.  */
  482.         long bytes_to_write = 0;
  483.         long *s = lbuf;
  484.  
  485.         while (nbytes-- > 0) {
  486.             c = *ptr++;
  487.             if (c == '\n') {
  488.                 if (bytes_to_write) {
  489.                     (*f->dev->write)(f, (char *)lbuf,
  490.                         bytes_to_write);
  491.                     bytes_to_write = 0;
  492.                     s = lbuf;
  493.                 }
  494.                 if (mode)    /* i.e. T_CRMODE */
  495.                     tty_putchar(f, cr_char, rwmode);
  496.                 tty_putchar(f, (long)c, rwmode);
  497.                 bytes_written++;
  498.             } else {
  499.                 *s++ = c;
  500.                 bytes_written++;
  501.                 bytes_to_write += 4;
  502.                 if (bytes_to_write >= LBUFSIZ*4) {
  503.                     (*f->dev->write)(f, (char *)lbuf,
  504.                              bytes_to_write);
  505.                     bytes_to_write = 0;
  506.                     s = lbuf;
  507.                 }
  508.             }
  509.         }
  510.         if (bytes_to_write) {
  511.             (*f->dev->write)(f, (char *)lbuf, bytes_to_write);
  512.         }
  513.     }
  514.  
  515.     return bytes_written;
  516. }
  517.  
  518. /* some notable scan codes */
  519. #define K_INSERT    0x52
  520. #define K_HOME        0x47
  521. #define K_UNDO        0x61
  522. #define K_HELP        0x62
  523. #define CURS_UP        0x48
  524. #define CURS_DN        0x50
  525. #define CURS_RT        0x4d
  526. #define CURS_LF        0x4b
  527. #define F_1        0x3b
  528. #define F_10        0x44
  529. #define F_11        0x54
  530. #define F_20        0x5d
  531. #define ALT_1        0x78
  532. #define ALT_0        0x81
  533.  
  534. /* Default function key table:
  535.  * entries:    0-9 are F1-F10
  536.  *            10-19 are F11-F20
  537.  *        20-23 are cursor up, down, right, and left
  538.  *        24-27 are help, undo, insert, and home
  539.  *        28-31 are shift+cursor up, down, right, and left
  540.  */
  541.  
  542. static char vt52xkey[256] = {
  543. '\033', 'P', 0, 0, 0, 0, 0, 0,
  544. '\033', 'Q', 0, 0, 0, 0, 0, 0,
  545. '\033', 'R', 0, 0, 0, 0, 0, 0,
  546. '\033', 'S', 0, 0, 0, 0, 0, 0,
  547. '\033', 'T', 0, 0, 0, 0, 0, 0,
  548. '\033', 'U', 0, 0, 0, 0, 0, 0,
  549. '\033', 'V', 0, 0, 0, 0, 0, 0,
  550. '\033', 'W', 0, 0, 0, 0, 0, 0,
  551. '\033', 'X', 0, 0, 0, 0, 0, 0,
  552. '\033', 'Y', 0, 0, 0, 0, 0, 0,
  553. '\033', 'p', 0, 0, 0, 0, 0, 0,
  554. '\033', 'q', 0, 0, 0, 0, 0, 0,
  555. '\033', 'r', 0, 0, 0, 0, 0, 0,
  556. '\033', 's', 0, 0, 0, 0, 0, 0,
  557. '\033', 't', 0, 0, 0, 0, 0, 0,
  558. '\033', 'u', 0, 0, 0, 0, 0, 0,
  559. '\033', 'v', 0, 0, 0, 0, 0, 0,
  560. '\033', 'w', 0, 0, 0, 0, 0, 0,
  561. '\033', 'x', 0, 0, 0, 0, 0, 0,
  562. '\033', 'y', 0, 0, 0, 0, 0, 0,
  563. '\033', 'A', 0, 0, 0, 0, 0, 0,
  564. '\033', 'B', 0, 0, 0, 0, 0, 0,
  565. '\033', 'C', 0, 0, 0, 0, 0, 0,
  566. '\033', 'D', 0, 0, 0, 0, 0, 0,
  567. '\033', 'H', 0, 0, 0, 0, 0, 0,
  568. '\033', 'K', 0, 0, 0, 0, 0, 0,
  569. '\033', 'I', 0, 0, 0, 0, 0, 0,
  570. '\033', 'E', 0, 0, 0, 0, 0, 0,
  571. '\033', 'a', 0, 0, 0, 0, 0, 0,
  572. '\033', 'b', 0, 0, 0, 0, 0, 0,
  573. '\033', 'c', 0, 0, 0, 0, 0, 0,
  574. '\033', 'd', 0, 0, 0, 0, 0, 0,
  575. };
  576.  
  577. static char unxbaud P_((long));
  578.  
  579. /* convert a number describing the baud rate into a Unix
  580.  * style baud rate number. Returns the Unix baud rate,
  581.  * or 16 (EXTA) if the rate is unknown
  582.  */
  583.  
  584. #define EXTA 16
  585.  
  586. static long ubaud[EXTA] = {
  587. 0L, 50L, 75L, 110L, 134L, 150L, 200L, 300L,
  588. 600L, 1200L, 1800L, 2400L, 4800L, 9600L, 19200L, 38400L
  589. };
  590.  
  591. static char
  592. unxbaud(baud)
  593.     long baud;
  594. {
  595.     int i;
  596.     for (i = 1; i < EXTA; i++) {
  597.         if (ubaud[i] == baud)
  598.             break;
  599.     }
  600.     return i;
  601. }
  602.  
  603. #define tosbaud(c) ( ((c) < 0 || (c) >= EXTA) ? -1L : ubaud[(unsigned)c] )
  604.  
  605. long
  606. tty_ioctl(f, mode, arg)
  607.     FILEPTR *f;
  608.     int mode;
  609.     void *arg;
  610. {
  611.     struct sgttyb *sg;
  612.     struct tchars *tc;
  613.     struct ltchars *ltc;
  614.     struct tty *tty;
  615.     struct winsize *sz;
  616.     struct xkey *xk;
  617.     char *xktab;
  618.     int i;
  619.     long baud;
  620.     short flags;
  621.     long outq;
  622.  
  623.     if (!is_terminal(f)) {
  624.         DEBUG(("tty_ioctl(mode %x): file is not a tty", mode));
  625.         return EINVFN;
  626.     }
  627.     tty = (struct tty *)f->devinfo;
  628.     assert(tty != 0);
  629.  
  630.     switch(mode) {
  631.     case FIONREAD:
  632.         {
  633.         long r;
  634.  
  635.         r = (*f->dev->ioctl)(f, FIONREAD, (void *)arg);
  636.         if (r || (f->flags & O_HEAD))
  637.             return r;
  638.         if (tty->state & TS_BLIND)
  639.             *(long *)arg = 0;
  640.         if ((tty->sg.sg_flags & T_XKEY) && (tty->state & TS_ESC) &&
  641.             !*(long *)arg)
  642.             *(long *)arg = 1;
  643.         return 0;
  644.         }
  645.     case FIONWRITE:
  646.         {
  647.         long r;
  648.  
  649.         r = (*f->dev->ioctl)(f, FIONWRITE, (void *)arg);
  650.         if (r || (f->flags & O_HEAD))
  651.             return r;
  652.         if ((tty->state & (TS_BLIND|TS_HOLD)))
  653.             *(long *)arg = 0;
  654.         return 0;
  655.         }
  656.     case TIOCSBRK:
  657.         if (!(tty->state & TS_BLIND) || (f->flags & O_HEAD))
  658.             return (*f->dev->ioctl)(f, TIOCSBRK, (void *)arg);
  659.         return 0;
  660.     case TIOCFLUSH:
  661.         {
  662.         long r;
  663.  
  664.         r = (*f->dev->ioctl)(f, TIOCFLUSH, (void *)arg);
  665.         if (r || (f->flags & O_HEAD))
  666.             return r;
  667.         if (!arg || (*(int *)arg & 1))
  668.             tty->state &= ~TS_ESC;
  669.         return 0;
  670.         }
  671.     case TIOCGETP:
  672.         {
  673.         unsigned long bits[2] = {-1, TF_FLAGS};
  674.         sg = (struct sgttyb *)arg;
  675.     /* get input and output baud rates from the terminal device */
  676.         baud = -1L;
  677.         (*f->dev->ioctl)(f, TIOCIBAUD, &baud);
  678.         tty->sg.sg_ispeed = unxbaud(baud);
  679.         baud = -1L;
  680.         (*f->dev->ioctl)(f, TIOCOBAUD, &baud);
  681.         tty->sg.sg_ospeed = unxbaud(baud);
  682.     /* get terminal flags */
  683.         flags = 0;
  684.         if ((*f->dev->ioctl)(f, TIOCSFLAGSB, &bits) == 0) {
  685.             tty->sg.sg_flags &= ~TF_FLAGS;
  686.             tty->sg.sg_flags |= (*bits & TF_FLAGS);
  687.         } else if ((*f->dev->ioctl)(f, TIOCGFLAGS, &flags) == 0) {
  688.             tty->sg.sg_flags &= ~TF_FLAGS;
  689.             tty->sg.sg_flags |= (flags & TF_FLAGS);
  690.         }
  691.         *sg = tty->sg;
  692.         return 0;
  693.         }
  694.     case TIOCSETP:
  695.         while (((*f->dev->ioctl)(f, TIOCOUTQ, &outq) == 0) && outq)
  696.             nap(200);
  697.         /* FALL THROUGH */
  698.     case TIOCSETN:
  699.         {
  700.         unsigned long bits[2];
  701.         static unsigned short v[] = {1, 0};
  702.         unsigned short oflags = tty->sg.sg_flags;
  703.  
  704.         sg = (struct sgttyb *)arg;
  705.         tty->sg = *sg;
  706.     /* change tty state */
  707.         if (sg->sg_flags & T_RAW) {
  708.             tty->state &= ~TS_COOKED;
  709.         } else {
  710.             tty->state |= TS_COOKED;
  711.         }
  712.         if (!(sg->sg_flags & T_XKEY)) {
  713.             tty->state &= ~TS_ESC;
  714.         }
  715.     /* set baud rates */
  716.         baud = tosbaud(sg->sg_ispeed);
  717.         (*f->dev->ioctl)(f, TIOCIBAUD, &baud);
  718.         baud = tosbaud(sg->sg_ospeed);
  719.         (*f->dev->ioctl)(f, TIOCOBAUD, &baud);
  720.     /* reset VMIN/VTIME */
  721.         if ((*f->dev->ioctl)(f, TIOCSVMIN, &v) < 0) {
  722.             tty->vmin = 1;
  723.             tty->vtime = 0;
  724.         }
  725.     /* set parity, etc. */
  726.         flags = TF_8BIT;
  727.         if (sg->sg_flags & (T_EVENP|T_ODDP)) {
  728.             flags = TF_7BIT;
  729.         }
  730.         flags |= (sg->sg_flags & TF_FLAGS);
  731.     /* default allow breaks to SIGINT unless RAW and no echo... */
  732.         if (!(sg->sg_flags & T_RAW) || (sg->sg_flags & T_ECHO))
  733.             flags |= TF_BRKINT;
  734.     /* leave local mode bit alone */
  735.         bits[0] = (unsigned)flags; bits[1] = ~TF_CAR;
  736.         if ((*f->dev->ioctl)(f, TIOCSFLAGSB, &bits) >= 0)
  737.             return 0;
  738.     /* if TIOCSFLAGSB failed clear TF_CAR, assume the device doesn't
  739.      * know about carrier anyway... */
  740.         if ((*f->dev->ioctl)(f, TIOCSFLAGS, &flags) >= 0)
  741.             return 0;
  742.     /* cannot set flags, don't save them */
  743.         tty->sg.sg_flags = (tty->sg.sg_flags & ~TF_FLAGS)|
  744.                         (oflags & TF_FLAGS);
  745.         return 0;
  746.         }
  747.     case TIOCGETC:
  748.         tc = (struct tchars *)arg;
  749.         *tc = tty->tc;
  750.         return 0;
  751.     case TIOCSETC:
  752.         tc = (struct tchars *)arg;
  753.         tty->tc = *tc;
  754.         return 0;
  755.     case TIOCGLTC:
  756.         ltc = (struct ltchars *)arg;
  757.         *ltc = tty->ltc;
  758.         return 0;
  759.     case TIOCSLTC:
  760.         ltc = (struct ltchars *)arg;
  761.         tty->ltc = *ltc;
  762.         return 0;
  763.     case TIOCGWINSZ:
  764.         sz = (struct winsize *)arg;
  765.         *sz = tty->wsiz;
  766.         return 0;
  767.     case TIOCSWINSZ:
  768.         sz = (struct winsize *)arg;
  769.         if (sz->ws_row != tty->wsiz.ws_row
  770.             || sz->ws_col != tty->wsiz.ws_col
  771.             || sz->ws_xpixel != tty->wsiz.ws_xpixel
  772.             || sz->ws_ypixel != tty->wsiz.ws_ypixel)
  773.           i = 1;
  774.         else
  775.           i = 0;
  776.         tty->wsiz = *sz;
  777.         if (i && tty->pgrp) killgroup(tty->pgrp, SIGWINCH, 1);
  778.         return 0;
  779.     case TIOCGPGRP:
  780.         *((long *)arg) = tty->pgrp;
  781.         return 0;
  782.     case TIOCSPGRP:
  783.         if (!tty->pgrp) {
  784.             tty->pgrp = (*((long *)arg) & 0x00007fffL);
  785.  
  786.             if (!(f->flags & O_NDELAY) && (tty->state & TS_BLIND))
  787.                 (*f->dev->ioctl)(f, TIOCWONLINE, 0);
  788.         } else {
  789.             tty->pgrp = (*((long *)arg) & 0x00007fffL);
  790.         }
  791.         return 0;
  792.     case TIOCSTART:
  793.         /* tty in the middle of a hangup? */
  794.         if (tty->hup_ospeed)
  795.             return 0;
  796. /* if the device has writeb writers may sleep for TS_HOLD (instead of polling),
  797.  * tell the device and wake them up
  798.  */
  799.         if (HAS_WRITEB(f)) {
  800.             (void)(*f->dev->ioctl)(f, TIOCSTART, &tty->state);
  801.             tty->state &= ~TS_HOLD;
  802.             wake (IO_Q, (long)&tty->state);
  803.         }
  804.         tty->state &= ~TS_HOLD;
  805.         if (tty->wsel) {
  806.             long r = 0;
  807.  
  808.             (void)(*f->dev->ioctl)(f, FIONWRITE, &r);
  809.             if (r && !(tty->state & TS_BLIND))
  810.                 wakeselect (tty->wsel);
  811.         }
  812.         return 0;
  813.     case TIOCSTOP:
  814.         if (HAS_WRITEB(f))
  815.             (void)(*f->dev->ioctl)(f, TIOCSTOP, &tty->state);
  816.         tty->state |= TS_HOLD;
  817.         return 0;
  818.     case TIOCGXKEY:
  819.         xk = (struct xkey *)arg;
  820.         i = xk->xk_num;
  821.         if (i < 0 || i > 31) return ERANGE;
  822.         xktab = tty->xkey;
  823.         if (!xktab) xktab = vt52xkey;
  824.         xktab += i*8;
  825.         for (i = 0; i < 8; i++)
  826.             xk->xk_def[i] = *xktab++;
  827.         return 0;
  828.     case TIOCSXKEY:
  829.         xk = (struct xkey *)arg;
  830.         xktab = tty->xkey;
  831.         if (!xktab) {
  832.             xktab = kmalloc((long)256);
  833.             if (!xktab) return ENSMEM;
  834.             for (i = 0; i < 256; i++)
  835.                 xktab[i] = vt52xkey[i];
  836.             tty->xkey = xktab;
  837.         }
  838.         i = xk->xk_num;
  839.         if (i < 0 || i > 31) return ERANGE;
  840.         xktab += i*8;
  841.         for (i = 0; i < 7; i++)
  842.             xktab[i] = xk->xk_def[i];
  843.         xktab[7] = 0;
  844.         return 0;
  845. /*
  846.  * change tty->state bits...  really only makes sense to touch TS_HPCL
  847.  * or maybe TS_COOKED.  (TS_HOLD is already handled by TIOCSTART/STOP)
  848.  */
  849.     case TIOCSSTATEB:
  850.         {
  851.         long mask = ((long *)arg)[1] & ~(TS_HOLD|TS_BLIND);
  852.         if (!(tty->sg.sg_flags & T_XKEY))
  853.             mask &= ~TS_ESC;
  854.         if (*(long *)arg != -1)
  855.             tty->state = (tty->state & ~mask) | (*((long *)arg) & mask);
  856.         *(long *)arg = tty->state;
  857.         return 0;
  858.         }
  859.     case TIOCGSTATE:
  860.         *(long *)arg = tty->state;
  861.         return 0;
  862. /* hang up on close, handled by kernel if the device understands TIOCOBAUD */
  863.     case TIOCHPCL:
  864.         tty->state |= TS_HPCL;
  865.         return 0;
  866. /* set/reset local mode */
  867.     case TIOCNCAR:
  868.     case TIOCCAR:
  869.         {
  870.         unsigned long bits[2] = {0, TF_CAR};
  871.         if (mode == TIOCCAR)
  872.             *bits = TF_CAR;
  873.         (*f->dev->ioctl)(f, TIOCSFLAGSB, &bits);
  874. /*
  875.  * if the ioctl failed the device does not know about carrier but don't
  876.  * return an error then since its the same as carrier always on
  877.  * (and anyway who puts a dialup line on a port that doesn't know
  878.  * how to SIGHUP or hang up safely... :)
  879.  */
  880.         return 0;
  881.         }
  882. /* emulate some new calls, they only get here when a device does not know them:
  883.  */
  884.     case TIOCSFLAGSB:
  885.         {
  886.         long fnew, mask = ((unsigned long *)arg)[1];
  887.         if (*(long *)arg < 0) {
  888.             (*f->dev->ioctl)(f, TIOCGFLAGS, &flags);
  889.             *((unsigned long *)arg) = flags;
  890.             return 0;
  891.         }
  892.         flags = 0;
  893.         if (mask != -1)
  894.             (*f->dev->ioctl)(f, TIOCGFLAGS, &flags);
  895.         fnew = (flags & ~mask) | (*((unsigned long *)arg) & mask);
  896.         if (mask == -1 || fnew != flags) {
  897.             flags = fnew;
  898.             (*f->dev->ioctl)(f, TIOCSFLAGS, &flags);
  899.             (*f->dev->ioctl)(f, TIOCGFLAGS, &flags);
  900.         }
  901.         *(unsigned long *)arg = flags;
  902.         return 0;
  903.         }
  904. /*
  905.  * tty_read handles VTIME itself but doing VMIN > 1 without support
  906.  * from the device won't be very efficient
  907.  */
  908.     case TIOCGVMIN:
  909.         ((unsigned short *)arg)[0] = 1;            /* VMIN */
  910.         ((unsigned short *)arg)[1] = tty->vtime;    /* VTIME */
  911.         return 0;
  912.     case TIOCSVMIN:
  913.         tty->vmin = 1;
  914.         tty->vtime = ((unsigned short *)arg)[1];
  915.         return 0;
  916. /* devices that don't know about carrier are always online... */
  917.     case TIOCWONLINE:
  918.         return 0;
  919. /* if the device didn't do TIOC[GS]FLAGS try transforming into TIOCSFLAGSB */
  920.     case TIOCGFLAGS:
  921.     case TIOCSFLAGS:
  922.         {
  923.         unsigned long bits[2] = {-1, (unsigned short)-1};
  924.         long r;
  925.  
  926.         if (mode == TIOCSFLAGS)
  927.             bits[0] = *(unsigned short *)arg;
  928.         r = (*f->dev->ioctl)(f, TIOCSFLAGSB, &bits);
  929.         if (!r && mode == TIOCGFLAGS)
  930.             *((unsigned short *)arg) = *bits;
  931.         return r;
  932.         }
  933. #ifdef MDM0_IOCTLS
  934. /*
  935.  * transform mdm0 ioctls, to allow old binaries run on new devices
  936.  * note this does nothing for the other way around i.e. transform the
  937.  * BSD ones (TIOCCAR/HPCL etc.) for mdm0...
  938.  */
  939.     case TIOCGHUPCL:
  940.         *(short *)arg = tty->state & TS_HPCL ? 1 : 0;
  941.         return 0;
  942.     case TIOCSHUPCL:
  943.         flags = *(short *)arg;
  944.         *(short *)arg = tty->state & TS_HPCL ? 1 : 0;
  945.         if (flags)
  946.             tty->state |= TS_HPCL;
  947.         else
  948.             tty->state &= ~TS_HPCL;
  949.         return 0;
  950.     case TIOCGSOFTCAR:
  951.         {
  952.         long bits[2];
  953.         flags = 1;
  954.         bits[0] = -1; bits[1] = TF_CAR;
  955.         if ((*f->dev->ioctl)(f, TIOCSFLAGSB, &bits) >= 0)
  956.             flags = bits[0] & TF_CAR ? 0 : 1;
  957.         *(short *)arg = flags;
  958.         return 0;
  959.         }
  960.     case TIOCSSOFTCAR:
  961.         {
  962.         long bits[2];
  963.         flags = 1;
  964.         bits[0] = *(short *)arg ? 0 : TF_CAR; bits[1] = TF_CAR;
  965.         if ((*f->dev->ioctl)(f, TIOCSFLAGSB, &bits) >= 0)
  966.             flags = bits[0] & TF_CAR ? 0 : 1;
  967.         *(short *)arg = flags;
  968.         return 0;
  969.         }
  970. #endif /* MDM0_IOCTLS */
  971.     default:
  972.         DEBUG(("tty_ioctl: bad function call"));
  973.         return EINVFN;
  974.     }
  975. }
  976.  
  977. /*
  978.  * function for translating extended characters (e.g. cursor keys, or
  979.  * ALT+key sequences) into either escape sequences or meta characters.
  980.  * for escape sequences, we return the the first character of the
  981.  * sequence (normally ESC) and set the tty's state so that subsequent
  982.  * calls to tty_getchar will pick up the remaining characters.
  983.  * Note that escape sequences are limited to 7 characters at most.
  984.  */
  985.  
  986. static int
  987. escseq(tty, scan)
  988.     struct tty *tty;
  989.     int scan;
  990. {
  991.     char *tab;
  992.     int i;
  993.  
  994.     switch(scan) {
  995.     case CURS_UP: i = 20; break;
  996.     case CURS_DN: i = 21; break;
  997.     case CURS_RT: i = 22; break;
  998.     case CURS_LF: i = 23; break;
  999.     case K_HELP:  i = 24; break;
  1000.     case K_UNDO:  i = 25; break;
  1001.     case K_INSERT:i = 26; break;
  1002.     case K_HOME:  i = 27; break;
  1003.     case CURS_UP+0x100: i = 28; break;
  1004.     case CURS_DN+0x100: i = 29; break;
  1005.     case CURS_RT+0x100: i = 30; break;
  1006.     case CURS_LF+0x100: i = 31; break;
  1007.     default:
  1008.         if (scan >= F_1 && scan <= F_10) {
  1009.             i = scan - F_1;
  1010.         } else if (scan >= F_11 && scan <= F_20) {
  1011.             i = 10 + scan - F_11;
  1012.         } else
  1013.             i = -1;
  1014.     }
  1015.  
  1016.     if (i >= 0) {        /* an extended escape sequence */
  1017.         tab = tty->xkey;
  1018.         if (!tab) tab = vt52xkey;
  1019.         i *= 8;
  1020.         scan = tab[i++];
  1021.         if (scan) {
  1022.             if (tab[i] == 0) i = 0;
  1023.             tty->state = (tty->state & ~TS_ESC) | i;
  1024.         }
  1025.         return scan;
  1026.     }
  1027.  
  1028.     if (scan >= ALT_1 && scan <= ALT_0) {
  1029.         scan -= (ALT_1-1);
  1030.         if (scan == 10) scan = 0;
  1031.         return (scan + '0') | 0x80;
  1032.     }
  1033.  
  1034.     tab = *( ((char **)Keytbl((void *)-1UL, (void *)-1UL, (void *)-1UL)) + 2 );    /* gratuitous (void *) for Lattice */
  1035.     scan = tab[scan];
  1036.     if (scan >= 'A' && scan <= 'Z') return scan | 0x80;
  1037.     return 0;
  1038. }
  1039.  
  1040. long
  1041. tty_getchar(f, mode)
  1042.     FILEPTR *f;
  1043.     int mode;
  1044. {
  1045.     struct tty *tty = (struct tty *)f->devinfo;
  1046.     char c, *tab;
  1047.     long r, ret;
  1048.     int scan;
  1049.     int master = f->flags & O_HEAD;
  1050.  
  1051.     assert(tty);
  1052.  
  1053. /* pty masters never worry about job control and always read in raw mode */
  1054.     if (master) {
  1055.         ret = (*f->dev->read)(f, (char *)&r, 4L);
  1056.         return (ret != 4L) ? MiNTEOF : r;
  1057.     }
  1058.  
  1059. /* job control check */
  1060.  
  1061. /*
  1062. entropy: only do the job control if SIGTTIN is neither blocked nor ignored,
  1063. and only for the controlling tty (IEEE 1003.1-1990 7.1.1.4 70-78).
  1064. BUG:  if the process group is orphaned or SIGTTIN *is* blocked or ignored,
  1065. we should return EIO instead of signalling.
  1066. */
  1067.  
  1068.     if ((tty->pgrp && tty->pgrp != curproc->pgrp) &&
  1069.             (f->fc.dev == curproc->control->fc.dev) &&
  1070.             (f->fc.index == curproc->control->fc.index)) {
  1071.         TRACE(("job control: tty pgrp is %d proc pgrp is %d",
  1072.             tty->pgrp, curproc->pgrp));
  1073.         killgroup(curproc->pgrp, SIGTTIN, 1);
  1074.         check_sigs();
  1075.     }
  1076.  
  1077.     if (mode & COOKED)
  1078.         tty->state |= TS_COOKED;
  1079.     else
  1080.         tty->state &= ~TS_COOKED;
  1081.  
  1082.     c = UNDEF+1;    /* set to UNDEF when we successfully read a character */
  1083.  
  1084. /* we may be in the middle of an escape sequence */
  1085.     scan = (tty->state & TS_ESC);
  1086.     if (scan != 0) {
  1087.         if (mode & ESCSEQ) {
  1088.             tab = tty->xkey ? tty->xkey : vt52xkey;
  1089.             r = (unsigned char) tab[scan++];
  1090.             if (r) {
  1091.                 c = UNDEF;
  1092.                 if (tab[scan] == 0) scan = 0;
  1093.             }
  1094.             else
  1095.                 scan = 0;
  1096.             tty->state = (tty->state & ~TS_ESC) | scan;
  1097.         }
  1098.         else
  1099.             tty->state &= ~TS_ESC;
  1100.     }
  1101.  
  1102.     while (c != UNDEF) {
  1103.         if (tty->state & TS_BLIND) {
  1104.             TRACE(("tty_getchar: offline"));
  1105.             return MiNTEOF;
  1106.         }
  1107.         ret = (*f->dev->read)(f, (char *)&r, 4L);
  1108.         if (ret != 4L) {
  1109.             DEBUG(("EOF on tty device"));
  1110.             return MiNTEOF;
  1111.         }
  1112.         c = r & 0x00ff;
  1113.         scan = (int)((r & 0x00ff0000L) >> 16);
  1114.         if ( (c == 0) && (mode & ESCSEQ) && scan) {
  1115.             c = UNDEF;
  1116.     /* translate cursor keys, etc. into escape sequences or
  1117.      * META characters
  1118.      */
  1119.             r = escseq(tty, scan);
  1120.         } else if ((mode & ESCSEQ) && ((scan == CURS_UP && c == '8') ||
  1121.                (scan == CURS_DN && c == '2') ||
  1122.                (scan == CURS_RT && c == '6') ||
  1123.                (scan == CURS_LF && c == '4'))) {
  1124.             c = UNDEF;
  1125.             r = escseq(tty, scan+0x100);
  1126.         } else if (mode & COOKED) {
  1127.             if (c == UNDEF)
  1128.                 ;    /* do nothing */
  1129.             else if (c == tty->ltc.t_dsuspc) {
  1130.                 killgroup(curproc->pgrp, SIGTSTP, 1);
  1131.                 check_sigs();
  1132.             } else if (c == tty->tc.t_intrc) {
  1133.                 killgroup(curproc->pgrp, SIGINT, 1);
  1134.                 check_sigs();
  1135.             } else if (c == tty->tc.t_quitc) {
  1136.                 killgroup(curproc->pgrp, SIGQUIT, 1);
  1137.                 check_sigs();
  1138.             } else if (c == tty->tc.t_stopc)
  1139.                 tty_ioctl(f, TIOCSTOP, 0);
  1140.             else if (c == tty->tc.t_startc)
  1141.                 tty_ioctl(f, TIOCSTART, 0);
  1142.             else
  1143.                 c = UNDEF;
  1144.         }
  1145.         else
  1146.                 c = UNDEF;
  1147.     }
  1148.  
  1149.     if (mode & ECHO)
  1150.         tty_putchar(f, r, mode);
  1151.  
  1152.     return r;
  1153. }
  1154.  
  1155. /*
  1156.  * tty_putchar: returns number of bytes successfully written
  1157.  */
  1158.  
  1159. long
  1160. tty_putchar(f, data, mode)
  1161.     FILEPTR *f;
  1162.     long data;
  1163.     int mode;
  1164. {
  1165.     struct tty *tty;
  1166.     int master;        /* file is pty master side */
  1167.     char ch;
  1168.  
  1169.     tty = (struct tty *)f->devinfo;
  1170.  
  1171.     master = f->flags & O_HEAD;
  1172.  
  1173. /* pty masters don't need to worry about job control */
  1174.     if (master) {
  1175.         ch = data & 0xff;
  1176.  
  1177.         if ( (tty->state & TS_COOKED) && ch != UNDEF) {
  1178.             long r = 1;
  1179.  
  1180. /* see if we're putting control characters into the buffer */
  1181.             if (ch == tty->tc.t_intrc) {
  1182.                 killgroup(tty->pgrp, SIGINT, 1);
  1183.                 if (!(tty->sg.sg_flags & T_NOFLSH))
  1184.                     tty_ioctl(f, TIOCFLUSH, &r);
  1185.                 tty_ioctl (f, TIOCSTART, 0);
  1186.                 return 4L;
  1187.             }
  1188.             else if (ch == tty->tc.t_quitc) {
  1189.                 killgroup(tty->pgrp, SIGQUIT, 1);
  1190.                 if (!(tty->sg.sg_flags & T_NOFLSH))
  1191.                     tty_ioctl(f, TIOCFLUSH, &r);
  1192.                 tty_ioctl (f, TIOCSTART, 0);
  1193.                 return 4L;
  1194.             }
  1195.             else if (ch == tty->ltc.t_suspc) {
  1196.                 killgroup(tty->pgrp, SIGTSTP, 1);
  1197.                 if (!(tty->sg.sg_flags & T_NOFLSH))
  1198.                     tty_ioctl(f, TIOCFLUSH, &r);
  1199.                 tty_ioctl (f, TIOCSTART, 0);
  1200.                 return 4L;
  1201.             }
  1202.             else if (ch == tty->tc.t_stopc) {
  1203.                 tty_ioctl (f, TIOCSTOP, 0);
  1204.                 return 4L;
  1205.             }
  1206.             else if (ch == tty->tc.t_startc) {
  1207.                 tty_ioctl (f, TIOCSTART, 0);
  1208.                 return 4L;
  1209.             }
  1210.             else if (ch == tty->ltc.t_flushc) {
  1211.                 long r = 2;
  1212.                 tty_ioctl (f, TIOCFLUSH, &r);
  1213.                 return 4L;
  1214.             }
  1215.             else if (tty->state & TS_HOLD) {
  1216.                 return 0;
  1217.             }
  1218.         }
  1219.         goto do_putchar;
  1220.     }
  1221. #if 1
  1222.     tty_checkttou(f, tty);
  1223. #else
  1224. /* job control checks */
  1225. /* AKP: added T_TOSTOP; don't stop BG output if T_TOSTOP is clear */
  1226. /*
  1227. entropy: only do the job control if SIGTTOU is neither blocked nor ignored,
  1228. and only for the controlling tty (IEEE 1003.1-1990 7.1.1.4 79-87).
  1229. BUG:  if the process group is orphaned and SIGTTOU *is not* blocked
  1230. or ignored, we should return EIO instead of signalling.
  1231. */
  1232.     if (tty->pgrp && tty->pgrp != curproc->pgrp &&
  1233.              (tty->sg.sg_flags & T_TOSTOP) &&
  1234.                  (curproc->sighandle[SIGTTOU] != SIG_IGN) &&
  1235.                  ((curproc->sigmask & (1L << SIGTTOU)) == 0L) &&
  1236.                  (f->fc.dev == curproc->control->fc.dev) &&
  1237.                  (f->fc.index == curproc->control->fc.index)) {
  1238.         TRACE(("job control: tty pgrp is %d proc pgrp is %d",
  1239.             tty->pgrp, curproc->pgrp));
  1240.         killgroup(curproc->pgrp, SIGTTOU, 1);
  1241.     }
  1242. #endif
  1243.  
  1244.     if (mode & COOKED) {
  1245.         tty->state |= TS_COOKED;
  1246.         while (tty->state & (TS_HOLD|TS_BLIND)) {
  1247.             short bdev;
  1248.             extern DEVDRV bios_tdevice;
  1249.  
  1250.             if (tty->state & TS_BLIND) {
  1251.                 TRACE(("tty_putchar: offline"));
  1252.                 return 0;
  1253.             }
  1254. #if 1
  1255.     /* hack: BIOS devices != console never reset TS_HOLD themselves
  1256.        unless another process happens to call tty_getchar on them while
  1257.        we're here.  someone has a better fix? :-(  -nox
  1258.     */
  1259. /* BIOS device definitions */
  1260. #define CONSDEV 2
  1261.             if (f->dev == &bios_tdevice &&
  1262.                 (bdev=f->fc.aux) != CONSDEV) {
  1263.                 long c;
  1264.  
  1265.                 if (!bconstat(bdev) ||
  1266.                     (c = bconin(bdev) & 0x7fffffffL) == UNDEF)
  1267.                     ;    /* do nothing */
  1268.                 else if (c == tty->ltc.t_suspc) {
  1269.                     tty_ioctl(f, TIOCSTART, 0);
  1270.                     killgroup(tty->pgrp, SIGTSTP, 1);
  1271.                 } else if (c == tty->tc.t_intrc) {
  1272.                     tty_ioctl(f, TIOCSTART, 0);
  1273.                     killgroup(tty->pgrp, SIGINT, 1);
  1274.                 } else if (c == tty->tc.t_quitc) {
  1275.                     tty_ioctl(f, TIOCSTART, 0);
  1276.                     killgroup(tty->pgrp, SIGQUIT, 1);
  1277.                 } else if (c == tty->tc.t_startc)
  1278.                     tty_ioctl(f, TIOCSTART, 0);
  1279.                 else if (c == tty->ltc.t_flushc) {
  1280.                     long r = 2;
  1281.                     tty_ioctl(f, TIOCFLUSH, &r);
  1282.                 }
  1283.             }
  1284.             else
  1285. #endif
  1286.             if (HAS_WRITEB(f)) {
  1287. /* if the device has writeb assume it wakes us when TS_HOLD resets */
  1288.                 sleep (IO_Q, (long)&tty->state);
  1289.                 continue;
  1290.             }
  1291.             nap(60);    /* sleep for 60 milliseconds */
  1292.         }
  1293.     }
  1294.     else
  1295.         tty->state &= ~TS_COOKED;
  1296.  
  1297. do_putchar:
  1298.     return (*f->dev->write)(f, (char *)&data, 4L);
  1299. }
  1300.  
  1301. /*
  1302.  * special select() function that takes T_XKEY into account
  1303.  */
  1304. long
  1305. tty_select(FILEPTR *f, long proc, int mode)
  1306. {
  1307.     struct tty *tty;
  1308.  
  1309.     tty = (struct tty *)f->devinfo;
  1310.     if (mode == O_RDONLY && (tty->sg.sg_flags & T_XKEY) &&
  1311.         (tty->state & TS_ESC))
  1312.         return 1;
  1313.     return (*f->dev->select)(f, proc, mode);
  1314. }
  1315.  
  1316.